﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Text;
using System.Windows.Forms;

namespace WFL.Windows.Forms
{
    public class TraditionalFormBase : ArcFormBase
    {

        #region 外观图片

        private Image _shut;
        public Image Shut
        {
            get { return _shut; }
            set { _shut = value; }
        }

        private Image _maximize;
        public Image Maximize
        {
            get { return _maximize; }
            set { _maximize = value; }
        }

        private Image _restore;
        public Image Restore
        {
            get { return _restore; }
            set { _restore = value; }
        }

        private Image _minimize;
        public Image Minimize
        {
            get { return _minimize; }
            set { _minimize = value; }
        }

        private Image _shutHover;
        public Image ShutHover
        {
            get { return _shutHover; }
            set { _shutHover = value; }
        }

        private Image _maximizeHover;
        public Image MaximizeHover
        {
            get { return _maximizeHover; }
            set { _maximizeHover = value; }
        }

        private Image _restoreHover;
        public Image RestoreHover
        {
            get { return _restoreHover; }
            set { _restoreHover = value; }
        }

        private Image _minimizeHover;
        public Image MinimizeHover
        {
            get { return _minimizeHover; }
            set { _minimizeHover = value; }
        }

        private Image _topLeft;
        public Image TopLeft
        {
            get { return _topLeft; }
            set { _topLeft = value; }
        }

        private Image _topRight;
        public Image TopRight
        {
            get { return _topRight; }
            set { _topRight = value; }
        }

        private Image _topCentre;
        public Image TopCentre
        {
            get { return _topCentre; }
            set { _topCentre = value; }
        }

        private Image _borderLeft;
        public Image BorderLeft
        {
            get { return _borderLeft; }
            set { _borderLeft = value; }
        }

        private Image _borderRight;
        public Image BorderRight
        {
            get { return _borderRight; }
            set { _borderRight = value; }
        }

        private Image _bottomLeft;
        public Image BottomLeft
        {
            get { return _bottomLeft; }
            set { _bottomLeft = value; }
        }

        private Image _bottomRight;
        public Image BottomRight
        {
            get { return _bottomRight; }
            set { _bottomRight = value; }
        }

        private Image _bottomCentre;
        public Image BottomCentre
        {
            get { return _bottomCentre; }
            set { _bottomCentre = value; }
        }

        #endregion


        private Size _iconSize;
        public Size IconSize
        {
            get { return _iconSize; }
            set
            {
                Size size = SystemInformation.SmallIconSize;
                if (value.Width < size.Width)
                {
                    value.Width = size.Width;
                }
                if (value.Height < size.Height)
                {
                    value.Height = size.Height;
                }
                if (_iconSize != value)
                {
                    _iconSize = value;
                }
            }
        }

        private Size _boxIndent;
        public Size BoxIndent
        {
            get { return _boxIndent; }
            set
            {
                if (value.Width < 0)
                {
                    value.Width = NcRightWidth;
                }
                if (value.Height < 0)
                {
                    value.Height = 0;
                }
                if (_boxIndent != value)
                {
                    _boxIndent = value;
                }
            }
        }

        public TraditionalFormBase()
        {
            _iconSize = new Size(20, 20);
            _boxIndent = new Size(NcRightWidth, 0);
        }

        protected virtual ColorMatrix GetNcInactiveColorMatrix()
        {
            float multi = 0.9f;
            float[][] matrix ={
                        new float[]{multi,0,0,0,0},
                        new float[]{0,multi,0,0,0},
                        new float[]{0,0,multi,0,0},
                        new float[]{0,0,0,1,0},
                        new float[]{0,0,0,0,1}
                        };
            return new ColorMatrix(matrix);
        }

        private void WmNcMouseMove(ref Message m)
        {
            Point point = new Point()
            {
                X = Header.Windowsx.GET_X_LPARAM(m.LParam),
                Y = Header.Windowsx.GET_Y_LPARAM(m.LParam)
            };
            point.Offset(-Left, -Top);
            if (!WmNcMouseMove(point))
            {
                base.WndProc(ref m);
            }
        }

        private void WmNcLButtonDown(ref Message m)
        {
            Point point = new Point()
            {
                X = Header.Windowsx.GET_X_LPARAM(m.LParam),
                Y = Header.Windowsx.GET_Y_LPARAM(m.LParam)
            };
            if (!WmNcLButtonDown(m.WParam.ToInt32(), point))
            {
                base.WndProc(ref m);
            }
        }

        private void WmNcLButtonUp(ref Message m)
        {
            Point point = new Point()
            {
                X = Header.Windowsx.GET_X_LPARAM(m.LParam),
                Y = Header.Windowsx.GET_Y_LPARAM(m.LParam)
            };
            if (!WmNcLButtonUp(m.WParam.ToInt32(), point))
            {
                base.WndProc(ref m);
            }
        }

        protected virtual bool WmNcMouseMove(Point point)
        {
            int box_x = Width - _boxIndent.Width;
            int box_y = _boxIndent.Height;
            if (WindowState == FormWindowState.Maximized)
            {
                //Windows 7行为，边框在屏幕外
                if (Left < 0)
                {
                    box_x += Left;
                }
                if (Top < 0)
                {
                    box_y -= Top;
                }
            }
            IntPtr hDC = IntPtr.Zero;
            Graphics graphics = null;
            try
            {
                if (_shut != null)
                {
                    box_x -= _shut.Width;
                    if (_shutHover != null)
                    {
                        if (graphics == null)
                        {
                            hDC = API.User32.GetWindowDC(Handle);
                            graphics = Graphics.FromHdc(hDC);
                        }
                        Image drawImage = _shut;
                        if (box_x < point.X && point.X < box_x + _shut.Width
                            && box_y < point.Y && point.Y < box_y + _shut.Height)
                        {
                            drawImage = _shutHover;
                        }
                        using (TextureBrush b = new TextureBrush(drawImage))
                        {
                            b.TranslateTransform(box_x, box_y);
                            graphics.FillRectangle(b, box_x, box_y, drawImage.Width, drawImage.Height);
                        }
                    }
                }
                if (MaximizeBox && _maximize != null && _restore != null)
                {
                    Image image = null, imageHover = null;
                    if (WindowState == FormWindowState.Normal)
                    {
                        image = _maximize;
                        imageHover = _maximizeHover;
                    }
                    else
                    {
                        image = _restore;
                        imageHover = _restoreHover;
                    }
                    box_x -= image.Width;
                    if (imageHover != null)
                    {
                        if (graphics == null)
                        {
                            hDC = API.User32.GetWindowDC(Handle);
                            graphics = Graphics.FromHdc(hDC);
                        }
                        Image drawImage = image;
                        if (box_x < point.X && point.X < box_x + image.Width
                            && box_y < point.Y && point.Y < box_y + image.Height)
                        {
                            drawImage = imageHover;
                        }
                        using (TextureBrush b = new TextureBrush(drawImage))
                        {
                            b.TranslateTransform(box_x, box_y);
                            graphics.FillRectangle(b, box_x, box_y, drawImage.Width, drawImage.Height);
                        }
                    }
                }
                if (MinimizeBox && _minimize != null)
                {
                    box_x -= _minimize.Width;
                    if (_minimizeHover != null)
                    {
                        if (graphics == null)
                        {
                            hDC = API.User32.GetWindowDC(Handle);
                            graphics = Graphics.FromHdc(hDC);
                        }
                        Image drawImage = _minimize;
                        if (box_x < point.X && point.X < box_x + _minimize.Width
                            && box_y < point.Y && point.Y < box_y + _minimize.Height)
                        {
                            drawImage = _minimizeHover;
                        }
                        using (TextureBrush b = new TextureBrush(drawImage))
                        {
                            b.TranslateTransform(box_x, box_y);
                            graphics.FillRectangle(b, box_x, box_y, drawImage.Width, drawImage.Height);
                        }
                    }
                }
                return true;
            }
            finally
            {
                if (graphics != null)
                {
                    graphics.Dispose();
                    API.User32.ReleaseDC(Handle, hDC);
                }
            }
        }

        private bool WmNcLButtonDown(int hit, Point point)
        {
            switch (hit)
            {
                default:
                    return false;
                case Header.Winuser.HTCLOSE:
                case Header.Winuser.HTMAXBUTTON:
                case Header.Winuser.HTMINBUTTON:
                    return true;
            }
        }

        private bool WmNcLButtonUp(int hit, Point point)
        {
            switch (hit)
            {
                default:
                    return false;
                case Header.Winuser.HTCLOSE:
                    {
                        Close();
                        return true;
                    }
                case Header.Winuser.HTMAXBUTTON:
                    {
                        if (WindowState == FormWindowState.Maximized)
                        {
                            WindowState = FormWindowState.Normal;
                        }
                        else
                        {
                            WindowState = FormWindowState.Maximized;
                        }
                        return true;
                    }
                case Header.Winuser.HTMINBUTTON:
                    {
                        WindowState = FormWindowState.Minimized;
                        return true;
                    }
            }
        }


        #region 绘制非客户区

        protected virtual void DrawTop(Graphics graphics, int state)
        {
            Rectangle scope = new Rectangle(0, 0, Width, NcTopHeight);
            using (Bitmap image = new Bitmap(scope.Width, scope.Height))
            {
                using (Graphics g = Graphics.FromImage(image))
                {
                    //绘制顶部区域
                    int width_l = 0, width_r = 0;
                    if (_topLeft != null)
                    {
                        width_l = _topLeft.Width;
                        using (TextureBrush b = new TextureBrush(_topLeft))
                        {
                            g.FillRectangle(b, 0, 0, width_l, scope.Height);
                        }
                    }
                    if (_topRight != null)
                    {
                        width_r = _topRight.Width;
                        using (TextureBrush b = new TextureBrush(_topRight))
                        {
                            b.TranslateTransform(scope.Width - width_r, 0);
                            g.FillRectangle(b, scope.Width - width_r, 0, width_r, scope.Height);
                        }
                    }
                    if (_topCentre != null)
                    {
                        using (TextureBrush b = new TextureBrush(_topCentre))
                        {
                            b.TranslateTransform(width_l, 0);
                            g.FillRectangle(b, width_l, 0, scope.Width - width_l - width_r, scope.Height);
                        }
                    }
                    //绘制关闭、最大化（还原）、最小化按钮
                    int box_x = scope.Width - _boxIndent.Width;
                    int box_y = _boxIndent.Height;
                    int box_width = 0;
                    if (WindowState == FormWindowState.Maximized)
                    {
                        //Windows 7行为，边框在屏幕外
                        if (Left < 0)
                        {
                            box_x += Left;
                        }
                        if (Top < 0)
                        {
                            box_y -= Top;
                        }
                    }
                    if (_shut != null)
                    {
                        box_width += _shut.Width;
                        box_x -= _shut.Width;
                        using (TextureBrush b = new TextureBrush(_shut))
                        {
                            b.TranslateTransform(box_x, box_y);
                            g.FillRectangle(b, box_x, box_y, _shut.Width, _shut.Height);
                        }
                    }
                    if (MaximizeBox && _maximize != null && _restore != null)
                    {
                        box_width += _maximize.Width;
                        box_x -= _maximize.Width;
                        if (WindowState == FormWindowState.Normal)
                        {
                            using (TextureBrush b = new TextureBrush(_maximize))
                            {
                                b.TranslateTransform(box_x, box_y);
                                g.FillRectangle(b, box_x, box_y, _maximize.Width, _maximize.Height);
                            }
                        }
                        else if (WindowState == FormWindowState.Maximized)
                        {
                            using (TextureBrush b = new TextureBrush(_restore))
                            {
                                b.TranslateTransform(box_x, box_y);
                                g.FillRectangle(b, box_x, box_y, _restore.Width, _restore.Height);
                            }
                        }
                    }
                    if (MinimizeBox && _minimize != null)
                    {
                        box_width += _minimize.Width;
                        box_x -= _minimize.Width;
                        using (TextureBrush b = new TextureBrush(_minimize))
                        {
                            b.TranslateTransform(box_x, box_y);
                            g.FillRectangle(b, box_x, box_y, _minimize.Width, _minimize.Height);
                        }
                    }
                    //绘制窗口图标
                    if (ShowIcon && Icon != null)
                    {
                        int y = (TitleHeight - _iconSize.Height) / 2;
                        if (y < 0)
                        {
                            y = 0;
                        }
                        y += NcTopBorderHeight;
                        g.DrawIcon(Icon, new Rectangle(NcLeftWidth, y, _iconSize.Width, _iconSize.Height));
                    }
                    //绘制窗口标题
                    if (!string.IsNullOrEmpty(Text))
                    {
                        SizeF fontSize = g.MeasureString(Text, Font);
                        float y = (TitleHeight - fontSize.Height) / 2;
                        if (y < 0)
                        {
                            y = 0;
                        }
                        y += NcTopBorderHeight;
                        int fontX = NcLeftWidth + 11;
                        if (ShowIcon && Icon != null)
                        {
                            fontX += _iconSize.Width;
                        }
                        int fontWidth = Width - fontX - box_width - _boxIndent.Width;
                        using (SolidBrush b = new SolidBrush(ForeColor))
                        {
                            g.DrawString(Text
                                , Font
                                , b
                                , new RectangleF(fontX, y, fontWidth, fontSize.Height)
                                , new StringFormat() { Trimming = StringTrimming.EllipsisCharacter });
                        }
                    }
                }
                //将顶部图片绘制到顶部区域
                ImageAttributes attr = null;
                if (state == -1)
                {
                    ColorMatrix matrix = GetNcInactiveColorMatrix();
                    if (matrix != null)
                    {
                        attr = new ImageAttributes();
                        attr.SetColorMatrix(matrix);
                    }
                }
                graphics.DrawImage(image, scope, 0, 0, scope.Width, scope.Height, GraphicsUnit.Pixel, attr);
            }
        }

        protected virtual void DrawBorder(Graphics graphics, int state)
        {
            ImageAttributes imageAttrs = null;
            //绘制左边框
            if (_borderLeft != null)
            {
                Rectangle scope = new Rectangle(0, NcTopHeight, NcLeftWidth, Height - NcHeight);
                using (Bitmap image = new Bitmap(scope.Width, scope.Height))
                {
                    using (Graphics g = Graphics.FromImage(image))
                    {
                        using (TextureBrush b = new TextureBrush(_borderLeft))
                        {
                            g.FillRectangle(b, 0, 0, scope.Width, scope.Height);
                        }
                    }
                    if (state == -1)
                    {
                        ColorMatrix matrix = GetNcInactiveColorMatrix();
                        if (matrix != null)
                        {
                            imageAttrs = new ImageAttributes();
                            imageAttrs.SetColorMatrix(matrix);
                        }
                    }
                    graphics.DrawImage(image, scope, 0, 0, scope.Width, scope.Height, GraphicsUnit.Pixel, imageAttrs);
                }
            }
            //绘制右边框
            if (_borderRight != null)
            {
                Rectangle scope = new Rectangle(Width - NcRightWidth, NcTopHeight, NcRightWidth, Height - NcHeight);
                using (Bitmap image = new Bitmap(scope.Width, scope.Height))
                {
                    using (Graphics g = Graphics.FromImage(image))
                    {
                        using (TextureBrush b = new TextureBrush(_borderRight))
                        {
                            g.FillRectangle(b, 0, 0, scope.Width, scope.Height);
                        }
                    }
                    if (state == -1 && imageAttrs == null)
                    {
                        ColorMatrix matrix = GetNcInactiveColorMatrix();
                        if (matrix != null)
                        {
                            imageAttrs = new ImageAttributes();
                            imageAttrs.SetColorMatrix(matrix);
                        }
                    }
                    graphics.DrawImage(image, scope, 0, 0, scope.Width, scope.Height, GraphicsUnit.Pixel, imageAttrs);
                }
            }
        }

        protected virtual void DrawBottom(Graphics graphics, int state)
        {
            Rectangle scope = new Rectangle(0, Height - NcBottomHeight, Width, NcBottomHeight);
            using (Bitmap image = new Bitmap(scope.Width, scope.Height))
            {
                using (Graphics g = Graphics.FromImage(image))
                {
                    //绘制底部边框
                    int width_l = 0, width_r = 0;
                    if (_bottomLeft != null)
                    {
                        width_l = _bottomLeft.Width;
                        using (TextureBrush b = new TextureBrush(_bottomLeft))
                        {
                            g.FillRectangle(b, 0, 0, width_l, scope.Height);
                        }
                    }
                    if (_bottomRight != null)
                    {
                        width_r = _bottomRight.Width;
                        using (TextureBrush b = new TextureBrush(_bottomRight))
                        {
                            b.TranslateTransform(scope.Width - width_r, 0);
                            g.FillRectangle(b, scope.Width - width_r, 0, width_r, scope.Height);
                        }
                    }
                    if (_bottomCentre != null)
                    {
                        using (TextureBrush b = new TextureBrush(_bottomCentre))
                        {
                            b.TranslateTransform(width_l, 0);
                            g.FillRectangle(b, width_l, 0, scope.Width - width_l - width_r, scope.Height);
                        }
                    }
                }
                ImageAttributes attr = null;
                if (state == -1)
                {
                    ColorMatrix matrix = GetNcInactiveColorMatrix();
                    if (matrix != null)
                    {
                        attr = new ImageAttributes();
                        attr.SetColorMatrix(matrix);
                    }
                }
                graphics.DrawImage(image, scope, 0, 0, scope.Width, scope.Height, GraphicsUnit.Pixel, attr);
            }
        }

        #endregion


        #region 重写基类方法

        protected override bool WmNcPaint(Graphics graphics)
        {
            if (WindowState != FormWindowState.Minimized)
            {
                int state = 0;
                DrawTop(graphics, state);
                DrawBorder(graphics, state);
                DrawBottom(graphics, state);
                return true;
            }
            return false;
        }

        protected override bool WmNcActivate(Graphics graphics, bool active)
        {
            if (WindowState != FormWindowState.Minimized)
            {
                int state = active ? 1 : -1;
                DrawTop(graphics, state);
                DrawBorder(graphics, state);
                DrawBottom(graphics, state);
                return true;
            }
            return false;
        }

        protected override int WmNcHitTest(Point point)
        {
            int box_x = Width - _boxIndent.Width;
            int box_y = _boxIndent.Height;
            if (_shut != null)
            {
                box_x -= _shut.Width;
                if (box_x < point.X && point.X < box_x + _shut.Width
                    && box_y < point.Y && point.Y < box_y + _shut.Height)
                {
                    return Header.Winuser.HTCLOSE;
                }
            }
            if (MaximizeBox && _maximize != null && _restore != null)
            {
                box_x -= _maximize.Width;
                if (box_x < point.X && point.X < box_x + _maximize.Width
                    && box_y < point.Y && point.Y < box_y + _maximize.Height)
                {
                    return Header.Winuser.HTMAXBUTTON;
                }
            }
            if (MinimizeBox && _minimize != null)
            {
                box_x -= _minimize.Width;
                if (box_x < point.X && point.X < box_x + _minimize.Width
                    && box_y < point.Y && point.Y < box_y + _minimize.Height)
                {
                    return Header.Winuser.HTMINBUTTON;
                }
            }
            return base.WmNcHitTest(point);
        }

        protected override void WndProc(ref Message m)
        {
            switch (m.Msg)
            {
                default:
                    base.WndProc(ref m);
                    break;
                case Header.Winuser.WM_NCMOUSEMOVE:
                    WmNcMouseMove(ref m);
                    break;
                case Header.Winuser.WM_NCLBUTTONDOWN:
                    WmNcLButtonDown(ref m);
                    break;
                case Header.Winuser.WM_NCLBUTTONUP:
                    WmNcLButtonUp(ref m);
                    break;
            }
        }

        #endregion


    }
}
